feat: add Google Gemini API proxy support (port 10003)#1640
feat: add Google Gemini API proxy support (port 10003)#1640
Conversation
Add full Gemini API proxy support to the AWF api-proxy sidecar, matching the pattern of existing OpenAI, Anthropic, and Copilot providers. This enables Gemini CLI to work inside the AWF sandbox without requiring workarounds in gh-aw. Changes: - Add GEMINI port 10003 to API_PROXY_PORTS - Add geminiApiKey, geminiApiTarget, geminiApiBasePath to WrapperConfig - Add --gemini-api-target and --gemini-api-base-path CLI flags - Add GEMINI_API_KEY to excluded env vars when api-proxy is enabled - Set placeholder GEMINI_API_KEY in agent container (Gemini CLI v0.65.0+ exits 41 without auth when GEMINI_API_BASE_URL is set) - Set GEMINI_API_BASE_URL pointing to sidecar in agent env - Add .gemini to whitelisted home subdirectories (bind mount + chroot) - Add Gemini proxy server in server.js using x-goog-api-key header - Expose port 10003 in Dockerfile Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 85.81% | 85.64% | 📉 -0.17% |
| Statements | 85.69% | 85.53% | 📉 -0.16% |
| Functions | 86.71% | 86.71% | ➡️ +0.00% |
| Branches | 78.50% | 78.02% | 📉 -0.48% |
📁 Per-file Coverage Changes (2 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/docker-manager.ts |
86.1% → 85.6% (-0.46%) | 85.6% → 85.2% (-0.44%) |
src/cli.ts |
60.6% → 60.6% (+0.02%) | 61.1% → 61.1% (+0.02%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
|
Smoke test results (run 23935548933) ✅ GitHub MCP: feat(smoke-claude): trim unused tools / fix: token analyzers always run Overall: PASS
|
Chroot Version Comparison Results
Overall: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.
|
|
Smoke Test (Codex)
|
There was a problem hiding this comment.
Pull request overview
Adds Google Gemini support to the existing API-proxy sidecar pattern so Gemini CLI can run in AWF mode without exposing the real API key to the agent container, while also ensuring Gemini CLI state (~/.gemini) is persisted in chroot mode.
Changes:
- Introduces a new Gemini proxy listener on port 10003 in the api-proxy sidecar, with support for custom target host/base-path and
x-goog-api-keyinjection. - Extends CLI/config/types to support
geminiApiKey,geminiApiTarget, andgeminiApiBasePathand wires them into Docker Compose generation. - Adds
~/.geminito the chroot home subdirectory allowlist and updates the corresponding test.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types.ts | Adds Gemini proxy port constant and new wrapper config fields for Gemini proxy settings. |
| src/docker-manager.ts | Wires Gemini env handling between agent and sidecar; mounts ~/.gemini; creates chroot dir. |
| src/docker-manager.test.ts | Updates expected chroot home subdirectories to include .gemini. |
| src/cli.ts | Adds Gemini API target/base-path flags and reads GEMINI_API_KEY into config; adds target warning/allowlist support. |
| containers/api-proxy/server.js | Adds Gemini proxy server on 10003 with key injection, health endpoint, and rate limiting. |
| containers/api-proxy/Dockerfile | Exposes port 10003 in the sidecar image. |
Comments suppressed due to low confidence (1)
src/cli.ts:1783
validateApiProxyConfig()/ API-proxy status logging elsewhere in this file still only consider OpenAI/Anthropic/Copilot. WithgeminiApiKeynow supported, running with onlyGEMINI_API_KEYwill emit a misleading "no API keys found" warning and omit Gemini from the status output. Update the validation + status log to include Gemini.
copilotGithubToken: process.env.COPILOT_GITHUB_TOKEN,
geminiApiKey: process.env.GEMINI_API_KEY,
copilotApiTarget: options.copilotApiTarget || process.env.COPILOT_API_TARGET,
openaiApiTarget: options.openaiApiTarget || process.env.OPENAI_API_TARGET,
openaiApiBasePath: options.openaiApiBasePath || process.env.OPENAI_API_BASE_PATH,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| openaiApiKey: process.env.OPENAI_API_KEY, | ||
| anthropicApiKey: process.env.ANTHROPIC_API_KEY, | ||
| copilotGithubToken: process.env.COPILOT_GITHUB_TOKEN, | ||
| geminiApiKey: process.env.GEMINI_API_KEY, | ||
| copilotApiTarget: options.copilotApiTarget || process.env.COPILOT_API_TARGET, |
There was a problem hiding this comment.
geminiApiKey is now being added to the runtime config object, but the later redaction logic only excludes openaiApiKey, anthropicApiKey, and copilotGithubToken. This will cause GEMINI_API_KEY to be logged in debug output via redactedConfig (secret disclosure). Add geminiApiKey to the redaction skip list (and any other secret-handling paths).
This issue also appears on line 1779 of the same file.
|
|
||
| proxyRequest(req, res, GEMINI_API_TARGET, { | ||
| 'x-goog-api-key': GEMINI_API_KEY, | ||
| }, 'gemini', GEMINI_API_BASE_PATH); | ||
| }); |
There was a problem hiding this comment.
Gemini auth is injected via x-goog-api-key, but the proxy’s auth-safety/logging paths are still oriented around authorization/x-api-key. Consider adding x-goog-api-key to the stripped header set and including it in the auth_inject debug logic so client-supplied Gemini keys are consistently removed/overwritten and injection can be observed in logs.
🔬 Smoke Test ResultsPR: feat: add Google Gemini API proxy support (port 10003)
Overall: PASS
|
Smoke Test: GitHub Actions Services Connectivity ✅All checks passed:
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Problem
Gemini CLI v0.65.0+ performs a startup auth check that exits with code 41 when
GEMINI_API_BASE_URLis set but noGEMINI_API_KEYis found. In AWF mode, the real key should be held by the api-proxy sidecar (not exposed to the agent container), but no Gemini proxy endpoint exists — forcing gh-aw to work around the issue by injecting placeholder keys andmkdircommands into the container command string.Additionally,
~/.gemini/is not in AWF's whitelisted home subdirectories, causing an ENOENT when Gemini CLI attempts to save its project registry.Upstream: github/gh-aw#23695 (gh-aw workaround for this gap)
Solution
Add full Gemini API proxy support following the same pattern as OpenAI, Anthropic, and Copilot providers:
API Proxy Sidecar (
containers/api-proxy/)server.jsGEMINI_API_KEYfrom env and injects it asx-goog-api-keyheader (Google API standard)GEMINI_API_TARGET, default:generativelanguage.googleapis.com) and base path prefix (GEMINI_API_BASE_PATH)CLI (
src/cli.ts)--gemini-api-target <host>and--gemini-api-base-path <path>flagsGEMINI_API_KEYread from env and passed to configemitApiProxyTargetWarnings()Docker Manager (
src/docker-manager.ts)GEMINI_API_KEYexcluded from agent env when api-proxy enabledGEMINI_API_KEY,GEMINI_API_TARGET,GEMINI_API_BASE_PATHpassed to sidecar containerGEMINI_API_BASE_URLset in agent container pointing to sidecar (http://172.30.0.30:10003)GEMINI_API_KEYset in agent so Gemini CLI's startup auth check passes.geminiadded to whitelisted home subdirectories (bind mount + chroot dir creation)Types (
src/types.ts)GEMINI: 10003added toAPI_PROXY_PORTSgeminiApiKey,geminiApiTarget,geminiApiBasePathadded toWrapperConfigHow it works
Once this lands, the
mkdir+ placeholder workaround in gh-aw#23695 can be simplified — AWF will handle both the~/.gemini/directory and the credential isolation natively.Testing
.gemini